package com.itee.javafx.controls;

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;

import java.math.BigDecimal;
import java.text.NumberFormat;
import java.text.ParseException;

/**
 * Created by gonglei on 14-4-21.
 */
public class NumberTextField extends LimitedTextField {

    private NumberFormat nf;


    private ObjectProperty<BigDecimal> number = new SimpleObjectProperty<>();


    private boolean plaintText = false;


    public final BigDecimal getNumber() {
        return number.get();
    }


    public final void setNumber(BigDecimal value) {
        number.set(value);
    }


    public ObjectProperty<BigDecimal> numberProperty() {
        return number;
    }


    public NumberTextField() {
        this(BigDecimal.ZERO);
    }


    public NumberTextField(BigDecimal value) {
        this(value, NumberFormat.getInstance());
    }


    public NumberTextField(BigDecimal value, NumberFormat nf) {
        super();
        this.nf = nf;
        initHandlers();
        setNumber(value);
    }

    private void initHandlers() {
        // try to parseMillions when focus is lost or RETURN is hit
        setOnAction(arg0 -> parseAndFormatInput());

        focusedProperty().addListener((observable, oldValue, newValue) -> {
            if (!newValue) {
                parseAndFormatInput();
            }
        });

        // Set text in field if BigDecimal property is changed from outside.
        numberProperty().addListener((obserable, oldValue, newValue) -> formatValue(newValue));
    }


    /**
     * Tries to parseMillions the user input to a number according to the provided
     * NumberFormat
     */
    private void parseAndFormatInput() {
        try {
            String input = getText();
            if (input == null || input.length() == 0) {
                return;
            }
            Number parsedNumber = NumberFormat.getInstance().parse(input);
            BigDecimal newValue = new BigDecimal(parsedNumber.toString());
            setNumber(newValue);
            formatValue(newValue);
        } catch (ParseException ex) {
            // If parsing fails keep old number
            formatValue(number.get());
        }
    }


    private void formatValue(BigDecimal value) {
        if (plaintText) {
            setText(value.toPlainString());
        } else {
            setText(nf.format(value));
        }
        verify();
    }


    public boolean isPlaintText() {
        return plaintText;
    }

    public void setPlaintText(boolean plaintText) {
        this.plaintText = plaintText;
    }
}

